package com.fangs.kotlin_banner

import com.fangs.kotlin_banner.utils.ProxyCacheUtils
import com.ivans.videocache.HttpUrlSource
import com.ivans.videocache.ProxyCacheException
import java.util.HashMap
import java.util.concurrent.Callable
import java.util.concurrent.Executors

/**
 * desc   : 视频预加载类
 * remark : 预加载成功才启动播放器开始播放 （此项目开屏启动页有用到此类）
 * version: 1.0
 */
class PreCacher private constructor() {
    private val preCacheExecutor = Executors.newFixedThreadPool(8)
    private val mCacheCallableMap: MutableMap<String, PreCacheCallable>

    /**
     * 开始缓存
     *
     * @param url        缓存的地址 (指结合本地代理的ProxyUrl 通过videocache库的getProxyUrl可获得)
     * @param cacheBytes 缓存大小（值大于0才生效 否则默认全部完整缓存 直至int最大值）
     */
    @Synchronized
    fun startCache(url: String, cacheBytes: Int) {
        if (mCacheCallableMap.containsKey(url)) {
            return
        }
        val cacheCallable: PreCacheCallable = PreCacheCallable(url, cacheBytes)
        mCacheCallableMap[url] = cacheCallable
        preCacheExecutor.submit(cacheCallable)
    }

    /**
     * 手动停止缓存
     *
     * @param url
     */
    @Synchronized
    fun stopCache(url: String) {
        val cacheCallable = mCacheCallableMap[url]
        if (cacheCallable != null) {
            cacheCallable.stop()
            mCacheCallableMap.remove(url)
        }
    }

    /**
     * 结束所有缓存操作
     */
    fun stopAll() {
        for (cacheCallable in mCacheCallableMap.values) {
            cacheCallable.stop()
        }
        mCacheCallableMap.clear()
    }

    private fun removePreCacheCallable(url: String) {
        val cacheCallable = mCacheCallableMap[url]
        if (cacheCallable != null) {
            mCacheCallableMap.remove(url)
        }
    }

    internal inner class PreCacheCallable(//缓存地址
        var mUrl: String, cacheBytes: Int
    ) : Callable<Boolean> {
        var mCacheSize = Int.MAX_VALUE //准备缓存的大小，单位bytes
        private var isStoped = false //停止缓存
        private val mStopLock = Any()
        var mSource: HttpUrlSource? = null
        override fun call(): Boolean {
            return connectToPoxyServer(mUrl)
        }

        fun stop() {
            synchronized(mStopLock) { isStoped = true }
        }

        //TODO 需不需要考虑retry等
        private fun connectToPoxyServer(url: String): Boolean {
            synchronized(mStopLock) {
                if (isStoped) {
                    return false
                }
            }
            mSource = HttpUrlSource(url)
            try {
                mSource!!.open(0)
                val buffer = ByteArray(ProxyCacheUtils.DEFAULT_BUFFER_SIZE)
                var readBytes: Int
                var offset = 0
                while (mSource!!.read(buffer).also { readBytes = it } != -1) {
                    synchronized(mStopLock) {
                        if (isStoped) {
                            return@synchronized
                        }
                    }
                    offset += readBytes
                    if (offset >= mCacheSize) {
                        break
                    }
                }
            } catch (e: ProxyCacheException) {
                e.printStackTrace()
                try {
                    mSource!!.close()
                } catch (proxyCacheException: ProxyCacheException) {
                    proxyCacheException.printStackTrace()
                }
                return false
            } finally {
                try {
                    mSource!!.close()
                    removePreCacheCallable(url)
                } catch (e: ProxyCacheException) {
                    e.printStackTrace()
                }
            }
            return true
        }

        init {
            if (cacheBytes > 0) {
                mCacheSize = cacheBytes
            }
        }
    }


    fun getInstance(): PreCacher? {
        return InstanceHolder.mInstance
    }

    internal object InstanceHolder {
        internal val mInstance: PreCacher = PreCacher()
    }

    companion object;
    init {
        mCacheCallableMap = HashMap()
    }
}